在完整的後端架構中,MVC 是一常見的設計模式。當 View 可以被框架內建,例如 Ruby on Rails 的 ERB 可以渲染 HTML,Go 則提供了 html/template。
html/template 對 text/template 進行了封裝,賦予其特定功能,以確保可以安全地使用模板。
tmpl, err := template.New("name").Parse(...)
// Error checking elided
err = tmpl.Execute(out, data)
使用這段程式碼,你可以創建並執行一個新的模板。
Execute
函式中的data
參數可能不是安全的,所以模板數入的數據如果是有害的,該包裝也會確保輸出是安全的我們來寫第一個範本吧
由於需要顯示在網頁上,所以我們也會需要用到上一個章節http的知識
故我們先把http及server架起來吧
package main
import (
"fmt"
"net/http"
)
func handlePage(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
}
func main() {
server := &http.Server{
Addr: ":8080",
}
http.HandleFunc("/", handlePage)
server.ListenAndServe()
}
架起來後我們再來把template加上去
package main
import (
"fmt"
"net/http"
)
func handlePage(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
// ADD HERE
tmpl, err := template.New("index").Parse(`<h1>{{.Title}}</h1>`)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func main() {
server := &http.Server{
Addr: ":8080",
}
http.HandleFunc("/", handlePage)
server.ListenAndServe()
}
接下來,我們要來注入資料結構
package main
import (
//Add here
"html/template"
"net/http"
)
type PageVariables struct {
Title string
}
func handlePage(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.New("index").Parse(`<h1>{{.Title}}</h1>`)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Add here
pageVariables := PageVariables{
Title: "Welcome to our website!",
}
err = tmpl.Execute(w, pageVariables)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func main() {
server := &http.Server{
Addr: ":8080",
}
http.HandleFunc("/", handlePage)
server.ListenAndServe()
}
範本語法會包含在 "{{" 和 "}}"中間,其中"{{.}}"中的典表示當前物件,再傳入結構物件時,可以根據"."來存取對應的欄位,以上個例子為例,我有一個結構物件名為"pageVariables"
type PageVariables struct {
Title string
}
pageVariables := PageVariables{
Title: "Welcome to our website!",
}
而我的樣本語法為
tmpl, err := template.New("index").Parse(`<h1>{{.Title}}</h1>`)
故,{.Title}就會被pageVariables的Title欄位替換
在go模板語法中, pipeline
是一種傳遞數據的機制,不一定要使用|
,只需要將一個表達式的結果傳遞給另一個表達式,直到最後的輸出,都可以稱為pipeline
在go的template語法裡,可以用以下pipeline的方式進行
{{.FieldName}}
,範本將會將數據結構中的FieldName傳入內{{ToLower .FieldName}}
首先從某個對象中取得.FieldName的值,然後傳遞給ToLower這個函數{{.Values | len}
{{.Field | default "No value"}}
在 Go 的 text/template 和 html/template 套件中,if 並不支援傳統的比較運算符如 <、>、== 等。這是為了確保模板的語法簡單和一致。
為了解決這個限制,Go 提供了一些特定的函數來完成這些比較操作。這些函數包括:
我們來看以下範例
type User struct {
Age int
Name string
}
func handlePage(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.New("index").Parse(`<h1>年紀</h1>
{{if lt .Age 18}}
<p>{{.Name}}, 你还未成年!</p>
{{else if lt .Age 60}}
<p>{{.Name}}, 你是一位成年人。</p>
{{else}}
<p>{{.Name}}, 你是一位长者。</p>
{{end}}`)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
u := User{Age: 15, Name: "Tom"}
err = tmpl.Execute(w, u)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func handlePage(w http.ResponseWriter, r *http.Request) {
people := map[string]int{
"Alice": 30,
"Bob": 25,
"Charlie": 35,
}
tmpl, err := template.New("index").Parse(`
<ul>
{{range $key, $value := .}}
<li>{{$key}}: {{$value}} years old</li>
{{end}}
</ul>
`)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
err = tmpl.Execute(w, people)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func main() {
server := &http.Server{
Addr: ":8080",
}
http.HandleFunc("/", handlePage)
server.ListenAndServe()
}